using Sage.CloudStorage.Qiniu.Auth;
using Sage.CloudStorage.Qiniu.Config;
using Sage.CloudStorage.Qiniu.Models;
using Sage.Http.Core;

namespace Sage.CloudStorage.Qiniu.Storage
{
    /// <summary>
    /// 存储桶管理器 - 提供对象存储相关功能
    /// </summary>
    /// <remarks>
    /// 提供对七牛云对象存储的管理功能，包括存储桶操作、文件操作等。
    /// </remarks>
    /// <remarks>
    /// 创建存储桶管理器实例
    /// </remarks>
    /// <param name="httpManager">HTTP请求管理器</param>
    /// <param name="key">七牛云密钥信息</param>
    /// <param name="config">七牛云配置</param>
    public class BucketManager(HttpRequestManager httpManager, QiniuKey key, QiniuConfig config)
    {
        private readonly HttpRequestManager _httpManager = httpManager ?? throw new ArgumentNullException(nameof(httpManager));
        private readonly QiniuKey _key = key ?? throw new ArgumentNullException(nameof(key));
        private readonly QiniuConfig _config = config ?? throw new ArgumentNullException(nameof(config));

        /// <summary>
        /// 获取存储桶列表
        /// </summary>
        /// <param name="shared">是否包含被授权访问的存储桶</param>
        /// <returns>存储桶列表</returns>
        public async Task<BucketListResult> GetBucketsAsync(bool shared = false)
        {
            string url = $"{_config.GetUcHost()}/buckets?shared={shared.ToString().ToLower()}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var response = await _httpManager.CreateRequest(HttpMethod.Get, url)
                .WithAuthentication(authProvider)
                .SendAsync();

            response.EnsureSuccessStatusCode();

            // 七牛云API返回的是字符串数组格式 ["bucket1", "bucket2", ...]
            // 而不是 {"buckets": ["bucket1", "bucket2", ...]} 格式
            // 所以需要先反序列化为字符串数组，再转换为BucketListResult
            var content = await response.Content.ReadAsStringAsync();
            var buckets = System.Text.Json.JsonSerializer.Deserialize<string[]>(content, QiniuJsonSerializerContext.Default.StringArray);

            return new BucketListResult { Buckets = buckets?.ToList() ?? [] };
        }

        /// <summary>
        /// 获取文件信息
        /// </summary>
        /// <param name="bucket">存储桶名称</param>
        /// <param name="key">文件键名</param>
        /// <returns>文件信息</returns>
        public async Task<FileInfoResult> GetFileInfoAsync(string bucket, string key)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentNullException(nameof(bucket));

            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException(nameof(key));

            string encodedEntry = Base64UrlSafeEncode($"{bucket}:{key}");
            string url = $"{_config.GetRsHost()}/stat/{encodedEntry}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var result = await _httpManager.CreateRequest(HttpMethod.Get, url)
                .WithAuthentication(authProvider)
                .SendAsJsonAsync(QiniuJsonSerializerContext.Default.FileInfoResult);

            return result ?? new FileInfoResult();
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="bucket">存储桶名称</param>
        /// <param name="key">文件键名</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> DeleteFileAsync(string bucket, string key)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentNullException(nameof(bucket));

            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException(nameof(key));

            string encodedEntry = Base64UrlSafeEncode($"{bucket}:{key}");
            string url = $"{_config.GetRsHost()}/delete/{encodedEntry}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var response = await _httpManager.CreateRequest(HttpMethod.Post, url)
                .WithAuthentication(authProvider)
                .SendAsync();

            return response.IsSuccessStatusCode;
        }

        /// <summary>
        /// 获取存储桶的域名列表
        /// </summary>
        /// <param name="bucket">存储桶名称</param>
        /// <returns>域名列表</returns>
        public async Task<DomainListResult> GetDomainsAsync(string bucket)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentNullException(nameof(bucket));

            string url = $"{_config.GetApiHost()}/v6/domain/list?tbl={bucket}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var response = await _httpManager.CreateRequest(HttpMethod.Get, url)
                .WithAuthentication(authProvider)
                .SendAsync();
            //.SendAsJsonAsync(QiniuJsonSerializerContext.Default.DomainListResult);


            response.EnsureSuccessStatusCode();

            // 七牛云API返回的是字符串数组格式 ["bucket1", "bucket2", ...]
            // 而不是 {"buckets": ["bucket1", "bucket2", ...]} 格式
            // 所以需要先反序列化为字符串数组，再转换为BucketListResult
            var content = await response.Content.ReadAsStringAsync();
            var Domains = System.Text.Json.JsonSerializer.Deserialize<string[]>(content, QiniuJsonSerializerContext.Default.StringArray);

            return new DomainListResult { Domains = Domains?.ToList() ?? [] };

        }

        /// <summary>
        /// 列举文件
        /// </summary>
        /// <param name="bucket">存储桶名称</param>
        /// <param name="prefix">前缀</param>
        /// <param name="marker">上次列举返回的位置标记</param>
        /// <param name="limit">每次返回的最大条目数</param>
        /// <returns>文件列表</returns>
        public async Task<FileListResult> ListFilesAsync(string bucket, string? prefix = null, string? marker = null, int limit = 1000)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentNullException(nameof(bucket));

            var queryParams = new Dictionary<string, string>
            {
                ["bucket"] = bucket,
                ["limit"] = limit.ToString()
            };

            if (!string.IsNullOrEmpty(prefix))
                queryParams["prefix"] = prefix;

            if (!string.IsNullOrEmpty(marker))
                queryParams["marker"] = marker;

            string queryString = string.Join("&", queryParams.Select(p => $"{p.Key}={Uri.EscapeDataString(p.Value)}"));
            string url = $"{_config.GetRsfHost()}/list?{queryString}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var result = await _httpManager.CreateRequest(HttpMethod.Get, url)
                .WithAuthentication(authProvider)
                .SendAsJsonAsync(QiniuJsonSerializerContext.Default.FileListResult);

            return result ?? new FileListResult();
        }

        /// <summary>
        /// 复制文件
        /// </summary>
        /// <param name="srcBucket">源存储桶</param>
        /// <param name="srcKey">源文件键名</param>
        /// <param name="destBucket">目标存储桶</param>
        /// <param name="destKey">目标文件键名</param>
        /// <param name="force">是否强制覆盖已有文件</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> CopyFileAsync(string srcBucket, string srcKey, string destBucket, string destKey, bool force = false)
        {
            if (string.IsNullOrEmpty(srcBucket))
                throw new ArgumentNullException(nameof(srcBucket));

            if (string.IsNullOrEmpty(srcKey))
                throw new ArgumentNullException(nameof(srcKey));

            if (string.IsNullOrEmpty(destBucket))
                throw new ArgumentNullException(nameof(destBucket));

            if (string.IsNullOrEmpty(destKey))
                throw new ArgumentNullException(nameof(destKey));

            string srcEntry = Base64UrlSafeEncode($"{srcBucket}:{srcKey}");
            string destEntry = Base64UrlSafeEncode($"{destBucket}:{destKey}");
            string url = $"{_config.GetRsHost()}/copy/{srcEntry}/{destEntry}/force/{(force ? 1 : 0)}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var response = await _httpManager.CreateRequest(HttpMethod.Post, url)
                .WithAuthentication(authProvider)
                .SendAsync();

            return response.IsSuccessStatusCode;
        }

        /// <summary>
        /// 移动文件
        /// </summary>
        /// <param name="srcBucket">源存储桶</param>
        /// <param name="srcKey">源文件键名</param>
        /// <param name="destBucket">目标存储桶</param>
        /// <param name="destKey">目标文件键名</param>
        /// <param name="force">是否强制覆盖已有文件</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> MoveFileAsync(string srcBucket, string srcKey, string destBucket, string destKey, bool force = false)
        {
            if (string.IsNullOrEmpty(srcBucket))
                throw new ArgumentNullException(nameof(srcBucket));

            if (string.IsNullOrEmpty(srcKey))
                throw new ArgumentNullException(nameof(srcKey));

            if (string.IsNullOrEmpty(destBucket))
                throw new ArgumentNullException(nameof(destBucket));

            if (string.IsNullOrEmpty(destKey))
                throw new ArgumentNullException(nameof(destKey));

            string srcEntry = Base64UrlSafeEncode($"{srcBucket}:{srcKey}");
            string destEntry = Base64UrlSafeEncode($"{destBucket}:{destKey}");
            string url = $"{_config.GetRsHost()}/move/{srcEntry}/{destEntry}/force/{(force ? 1 : 0)}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var response = await _httpManager.CreateRequest(HttpMethod.Post, url)
                .WithAuthentication(authProvider)
                .SendAsync();

            return response.IsSuccessStatusCode;
        }

        /// <summary>
        /// 修改文件类型
        /// </summary>
        /// <param name="bucket">存储桶名称</param>
        /// <param name="key">文件键名</param>
        /// <param name="mimeType">新的MIME类型</param>
        /// <returns>操作是否成功</returns>
        public async Task<bool> ChangeMimeTypeAsync(string bucket, string key, string mimeType)
        {
            if (string.IsNullOrEmpty(bucket))
                throw new ArgumentNullException(nameof(bucket));

            if (string.IsNullOrEmpty(key))
                throw new ArgumentNullException(nameof(key));

            if (string.IsNullOrEmpty(mimeType))
                throw new ArgumentNullException(nameof(mimeType));

            string encodedEntry = Base64UrlSafeEncode($"{bucket}:{key}");
            string encodedMimeType = Base64UrlSafeEncode(mimeType);
            string url = $"{_config.GetRsHost()}/chgm/{encodedEntry}/mime/{encodedMimeType}";

            var authProvider = new QiniuAuthProvider(_key, QiniuAuthType.ManageApiV2);
            var response = await _httpManager.CreateRequest(HttpMethod.Post, url)
                .WithAuthentication(authProvider)
                .SendAsync();

            return response.IsSuccessStatusCode;
        }

        /// <summary>
        /// Base64 URL安全编码
        /// </summary>
        /// <param name="text">要编码的文本</param>
        /// <returns>编码后的文本</returns>
        private static string Base64UrlSafeEncode(string text)
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(text);
            string base64 = Convert.ToBase64String(bytes);
            return base64.Replace("+", "-").Replace("/", "_");
        }
    }

    #region 结果类

    /// <summary>
    /// 存储桶列表结果
    /// </summary>
    public class BucketListResult
    {
        /// <summary>
        /// 存储桶列表
        /// </summary>
        public List<string> Buckets { get; set; } = [];
    }

    /// <summary>
    /// 文件信息结果
    /// </summary>
    public class FileInfoResult
    {
        /// <summary>
        /// 文件哈希值（ETAG）
        /// </summary>
        public string Hash { get; set; } = string.Empty;

        /// <summary>
        /// 文件大小（字节）
        /// </summary>
        public long FSize { get; set; }

        /// <summary>
        /// 文件MIME类型
        /// </summary>
        public string MimeType { get; set; } = string.Empty;

        /// <summary>
        /// 文件上传时间（Unix时间戳，单位为秒）
        /// </summary>
        public long PutTime { get; set; }

        /// <summary>
        /// 文件类型（0表示普通文件，1表示目录）
        /// </summary>
        public int Type { get; set; }

        /// <summary>
        /// 文件状态（0表示启用，1表示禁用）
        /// </summary>
        public int Status { get; set; }
    }

    /// <summary>
    /// 域名列表结果
    /// </summary>
    public class DomainListResult
    {
        /// <summary>
        /// 域名列表
        /// </summary>
        public List<string> Domains { get; set; } = [];
    }

    /// <summary>
    /// 文件列表结果
    /// </summary>
    public class FileListResult
    {
        /// <summary>
        /// 文件列表
        /// </summary>
        public List<FileItem> Items { get; set; } = [];

        /// <summary>
        /// 下一次列举的位置标记
        /// </summary>
        public string? Marker { get; set; }

        /// <summary>
        /// 是否已经列举完毕
        /// </summary>
        public bool IsEOF { get; set; }
    }

    /// <summary>
    /// 文件项
    /// </summary>
    public class FileItem
    {
        /// <summary>
        /// 文件键名
        /// </summary>
        public string Key { get; set; } = string.Empty;

        /// <summary>
        /// 文件哈希值（ETAG）
        /// </summary>
        public string Hash { get; set; } = string.Empty;

        /// <summary>
        /// 文件大小（字节）
        /// </summary>
        public long FSize { get; set; }

        /// <summary>
        /// 文件MIME类型
        /// </summary>
        public string MimeType { get; set; } = string.Empty;

        /// <summary>
        /// 文件上传时间（Unix时间戳，单位为秒）
        /// </summary>
        public long PutTime { get; set; }

        /// <summary>
        /// 文件类型（0表示普通文件，1表示目录）
        /// </summary>
        public int Type { get; set; }

        /// <summary>
        /// 文件状态（0表示启用，1表示禁用）
        /// </summary>
        public int Status { get; set; }
    }

    #endregion
}